/******************************************************************************* * Copyright (c) 2000, 2012 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.swt.widgets; import org.eclipse.swt.internal.win32.*; import org.eclipse.swt.*; import org.eclipse.swt.events.*; import org.eclipse.swt.graphics.*; /** * Instances of this class are selectable user interface * objects that allow the user to enter and modify date * or time values. * <p> * Note that although this class is a subclass of <code>Composite</code>, * it does not make sense to add children to it, or set a layout on it. * </p> * <dl> * <dt><b>Styles:</b></dt> * <dd>DATE, TIME, CALENDAR, SHORT, MEDIUM, LONG, DROP_DOWN</dd> * <dt><b>Events:</b></dt> * <dd>DefaultSelection, Selection</dd> * </dl> * <p> * Note: Only one of the styles DATE, TIME, or CALENDAR may be specified, * and only one of the styles SHORT, MEDIUM, or LONG may be specified. * The DROP_DOWN style is a <em>HINT</em>, and it is only valid with the DATE style. * </p><p> * IMPORTANT: This class is <em>not</em> intended to be subclassed. * </p> * * @see <a href="http://www.eclipse.org/swt/snippets/#datetime">DateTime snippets</a> * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a> * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> * * @since 3.3 * @noextend This class is not intended to be subclassed by clients. */ public class DateTime extends Composite { static final int MIN_YEAR = 1752; // Gregorian switchover in North America: September 19, 1752 static final int MAX_YEAR = 9999; boolean doubleClick, ignoreSelection; SYSTEMTIME lastSystemTime; SYSTEMTIME time = new SYSTEMTIME (); // only used in calendar mode static final long /*int*/ DateTimeProc; static final TCHAR DateTimeClass = new TCHAR (0, OS.DATETIMEPICK_CLASS, true); static final long /*int*/ CalendarProc; static final TCHAR CalendarClass = new TCHAR (0, OS.MONTHCAL_CLASS, true); static { INITCOMMONCONTROLSEX icex = new INITCOMMONCONTROLSEX (); icex.dwSize = INITCOMMONCONTROLSEX.sizeof; icex.dwICC = OS.ICC_DATE_CLASSES; OS.InitCommonControlsEx (icex); } static { WNDCLASS lpWndClass = new WNDCLASS (); OS.GetClassInfo (0, DateTimeClass, lpWndClass); DateTimeProc = lpWndClass.lpfnWndProc; /* * Feature in Windows. The date time window class * does not include CS_DBLCLKS. This means that these * controls will not get double click messages such as * WM_LBUTTONDBLCLK. The fix is to register a new * window class with CS_DBLCLKS. * * NOTE: Screen readers look for the exact class name * of the control in order to provide the correct kind * of assistance. Therefore, it is critical that the * new window class have the same name. It is possible * to register a local window class with the same name * as a global class. Since bits that affect the class * are being changed, it is possible that other native * code, other than SWT, could create a control with * this class name, and fail unexpectedly. */ long /*int*/ hInstance = OS.GetModuleHandle (null); long /*int*/ hHeap = OS.GetProcessHeap (); lpWndClass.hInstance = hInstance; lpWndClass.style &= ~OS.CS_GLOBALCLASS; lpWndClass.style |= OS.CS_DBLCLKS; int byteCount = DateTimeClass.length () * TCHAR.sizeof; long /*int*/ lpszClassName = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount); OS.MoveMemory (lpszClassName, DateTimeClass, byteCount); lpWndClass.lpszClassName = lpszClassName; OS.RegisterClass (lpWndClass); OS.HeapFree (hHeap, 0, lpszClassName); } static { WNDCLASS lpWndClass = new WNDCLASS (); OS.GetClassInfo (0, CalendarClass, lpWndClass); CalendarProc = lpWndClass.lpfnWndProc; /* * Feature in Windows. The date time window class * does not include CS_DBLCLKS. This means that these * controls will not get double click messages such as * WM_LBUTTONDBLCLK. The fix is to register a new * window class with CS_DBLCLKS. * * NOTE: Screen readers look for the exact class name * of the control in order to provide the correct kind * of assistance. Therefore, it is critical that the * new window class have the same name. It is possible * to register a local window class with the same name * as a global class. Since bits that affect the class * are being changed, it is possible that other native * code, other than SWT, could create a control with * this class name, and fail unexpectedly. */ long /*int*/ hInstance = OS.GetModuleHandle (null); long /*int*/ hHeap = OS.GetProcessHeap (); lpWndClass.hInstance = hInstance; lpWndClass.style &= ~OS.CS_GLOBALCLASS; lpWndClass.style |= OS.CS_DBLCLKS; int byteCount = CalendarClass.length () * TCHAR.sizeof; long /*int*/ lpszClassName = OS.HeapAlloc (hHeap, OS.HEAP_ZERO_MEMORY, byteCount); OS.MoveMemory (lpszClassName, CalendarClass, byteCount); lpWndClass.lpszClassName = lpszClassName; OS.RegisterClass (lpWndClass); OS.HeapFree (hHeap, 0, lpszClassName); } static final int MARGIN = 4; static final int MAX_DIGIT = 9; static final int MAX_DAY = 31; static final int MAX_12HOUR = 12; static final int MAX_24HOUR = 24; static final int MAX_MINUTE = 60; static final int MONTH_DAY_YEAR = 0; static final int DAY_MONTH_YEAR = 1; static final int YEAR_MONTH_DAY = 2; static final char SINGLE_QUOTE = '\''; //$NON-NLS-1$ short date format may include quoted text static final char DAY_FORMAT_CONSTANT = 'd'; //$NON-NLS-1$ 1-4 lowercase 'd's represent day static final char MONTH_FORMAT_CONSTANT = 'M'; //$NON-NLS-1$ 1-4 uppercase 'M's represent month static final char YEAR_FORMAT_CONSTANT = 'y'; //$NON-NLS-1$ 1-5 lowercase 'y's represent year static final char HOURS_FORMAT_CONSTANT = 'h'; //$NON-NLS-1$ 1-2 upper or lowercase 'h's represent hours static final char MINUTES_FORMAT_CONSTANT = 'm'; //$NON-NLS-1$ 1-2 lowercase 'm's represent minutes static final char SECONDS_FORMAT_CONSTANT = 's'; //$NON-NLS-1$ 1-2 lowercase 's's represent seconds static final char AMPM_FORMAT_CONSTANT = 't'; //$NON-NLS-1$ 1-2 lowercase 't's represent am/pm static final int[] MONTH_NAMES = new int[] {OS.LOCALE_SMONTHNAME1, OS.LOCALE_SMONTHNAME2, OS.LOCALE_SMONTHNAME3, OS.LOCALE_SMONTHNAME4, OS.LOCALE_SMONTHNAME5, OS.LOCALE_SMONTHNAME6, OS.LOCALE_SMONTHNAME7, OS.LOCALE_SMONTHNAME8, OS.LOCALE_SMONTHNAME9, OS.LOCALE_SMONTHNAME10, OS.LOCALE_SMONTHNAME11, OS.LOCALE_SMONTHNAME12}; /** * Constructs a new instance of this class given its parent * and a style value describing its behavior and appearance. * <p> * The style value is either one of the style constants defined in * class <code>SWT</code> which is applicable to instances of this * class, or must be built by <em>bitwise OR</em>'ing together * (that is, using the <code>int</code> "|" operator) two or more * of those <code>SWT</code> style constants. The class description * lists the style constants that are applicable to the class. * Style bits are also inherited from superclasses. * </p> * * @param parent a composite control which will be the parent of the new instance (cannot be null) * @param style the style of control to construct * * @exception IllegalArgumentException <ul> * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> * </ul> * @exception SWTException <ul> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> * </ul> * * @see SWT#DATE * @see SWT#TIME * @see SWT#CALENDAR * @see SWT#SHORT * @see SWT#MEDIUM * @see SWT#LONG * @see SWT#DROP_DOWN * @see Widget#checkSubclass * @see Widget#getStyle */ public DateTime (Composite parent, int style) { super (parent, checkStyle (style)); if ((this.style & SWT.SHORT) != 0) { String buffer = ((this.style & SWT.DATE) != 0) ? getCustomShortDateFormat() : getCustomShortTimeFormat(); TCHAR lpszFormat = new TCHAR (0, buffer, true); OS.SendMessage (handle, OS.DTM_SETFORMAT, 0, lpszFormat); } } /** * Adds the listener to the collection of listeners who will * be notified when the control is selected by the user, by sending * it one of the messages defined in the <code>SelectionListener</code> * interface. * <p> * <code>widgetSelected</code> is called when the user changes the control's value. * <code>widgetDefaultSelected</code> is typically called when ENTER is pressed. * </p> * * @param listener the listener which should be notified * * @exception IllegalArgumentException <ul> * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> * </ul> * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> * * @see SelectionListener * @see #removeSelectionListener * @see SelectionEvent */ public void addSelectionListener (SelectionListener listener) { checkWidget (); if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); TypedListener typedListener = new TypedListener (listener); addListener (SWT.Selection, typedListener); addListener (SWT.DefaultSelection, typedListener); } long /*int*/ callWindowProc (long /*int*/ hwnd, int msg, long /*int*/ wParam, long /*int*/ lParam) { if (handle == 0) return 0; return OS.CallWindowProc (windowProc (), hwnd, msg, wParam, lParam); } static int checkStyle (int style) { /* * Even though it is legal to create this widget * with scroll bars, they serve no useful purpose * because they do not automatically scroll the * widget's client area. The fix is to clear * the SWT style. */ style &= ~(SWT.H_SCROLL | SWT.V_SCROLL); style = checkBits (style, SWT.DATE, SWT.TIME, SWT.CALENDAR, 0, 0, 0); style = checkBits (style, SWT.MEDIUM, SWT.SHORT, SWT.LONG, 0, 0, 0); if ((style & SWT.DATE) == 0) style &=~ SWT.DROP_DOWN; return style; } protected void checkSubclass () { if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS); } public Point computeSize (int wHint, int hHint, boolean changed) { checkWidget (); int width = 0, height = 0; if (wHint == SWT.DEFAULT || hHint == SWT.DEFAULT) { if ((style & SWT.CALENDAR) != 0) { RECT rect = new RECT (); OS.SendMessage(handle, OS.MCM_GETMINREQRECT, 0, rect); width = rect.right; height = rect.bottom; } else { if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) { /* Vista and later: use DTM_GETIDEALSIZE. */ SIZE size = new SIZE (); OS.SendMessage(handle, OS.DTM_GETIDEALSIZE, 0, size); width = size.cx; height = size.cy; } else { long /*int*/ newFont, oldFont = 0; long /*int*/ hDC = OS.GetDC (handle); newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont); RECT rect = new RECT (); if ((style & SWT.DATE) != 0) { int dwFlags = 0; TCHAR lpFormat = null; if ((style & SWT.SHORT) != 0) { lpFormat = new TCHAR (0, getCustomShortDateFormat(), true); } else { dwFlags = (style & SWT.MEDIUM) != 0 ? OS.DATE_SHORTDATE : OS.DATE_LONGDATE; } int size = OS.GetDateFormat(OS.LOCALE_USER_DEFAULT, dwFlags, null, lpFormat, null, 0); if (size > 0) { TCHAR buffer = new TCHAR (getCodePage (), size); OS.GetDateFormat(OS.LOCALE_USER_DEFAULT, dwFlags, null, lpFormat, buffer, buffer.length ()); OS.DrawText (hDC, buffer, size, rect, OS.DT_CALCRECT | OS.DT_EDITCONTROL); } } else if ((style & SWT.TIME) != 0) { int dwFlags = 0; TCHAR lpFormat = null; if ((style & SWT.SHORT) != 0) { dwFlags = OS.TIME_NOSECONDS; lpFormat = new TCHAR (0, getCustomShortTimeFormat(), true); } int size = OS.GetTimeFormat(OS.LOCALE_USER_DEFAULT, dwFlags, null, lpFormat, null, 0); if (size > 0) { TCHAR buffer = new TCHAR (getCodePage (), size); OS.GetTimeFormat(OS.LOCALE_USER_DEFAULT, dwFlags, null, lpFormat, buffer, buffer.length ()); OS.DrawText (hDC, buffer, size, rect, OS.DT_CALCRECT | OS.DT_EDITCONTROL); } } width = rect.right - rect.left; height = rect.bottom - rect.top; if (newFont != 0) OS.SelectObject (hDC, oldFont); OS.ReleaseDC (handle, hDC); int upDownWidth = OS.GetSystemMetrics (OS.SM_CXVSCROLL); width += upDownWidth + MARGIN; } int upDownHeight = OS.GetSystemMetrics (OS.SM_CYVSCROLL); if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (6, 0)) { // TODO: Can maybe use DTM_GETDATETIMEPICKERINFO for this upDownHeight += 7; } height = Math.max (height, upDownHeight); } } if (width == 0) width = DEFAULT_WIDTH; if (height == 0) height = DEFAULT_HEIGHT; if (wHint != SWT.DEFAULT) width = wHint; if (hHint != SWT.DEFAULT) height = hHint; int border = getBorderWidth (); width += border * 2; height += border * 2; return new Point (width, height); } void createHandle () { super.createHandle (); state &= ~(CANVAS | THEME_BACKGROUND); if ((style & SWT.BORDER) == 0) { int bits = OS.GetWindowLong (handle, OS.GWL_EXSTYLE); bits &= ~(OS.WS_EX_CLIENTEDGE | OS.WS_EX_STATICEDGE); OS.SetWindowLong (handle, OS.GWL_EXSTYLE, bits); } } int defaultBackground () { return OS.GetSysColor (OS.COLOR_WINDOW); } String getCustomShortDateFormat () { TCHAR tchar = new TCHAR (getCodePage (), 80); int size = OS.GetLocaleInfo (OS.LOCALE_USER_DEFAULT, OS.LOCALE_SYEARMONTH, tchar, 80); return size != 0 ? tchar.toString (0, size - 1) : "M/yyyy"; //$NON-NLS-1$ } String getCustomShortTimeFormat () { StringBuffer buffer = new StringBuffer (getTimeFormat ()); int length = buffer.length (); boolean inQuotes = false; int start = 0, end = 0; while (start < length) { char ch = buffer.charAt (start); if (ch == SINGLE_QUOTE) inQuotes = !inQuotes; else if (ch == SECONDS_FORMAT_CONSTANT && !inQuotes) { end = start + 1; while (end < length && buffer.charAt (end) == SECONDS_FORMAT_CONSTANT) end++; // skip the preceding separator while (start > 0 && buffer.charAt (start) != MINUTES_FORMAT_CONSTANT) start--; start++; break; } start++; } if (start < end) buffer.delete (start, end); return buffer.toString (); } String getTimeFormat () { TCHAR tchar = new TCHAR (getCodePage (), 80); int size = OS.GetLocaleInfo (OS.LOCALE_USER_DEFAULT, OS.LOCALE_STIMEFORMAT, tchar, 80); return size > 0 ? tchar.toString (0, size - 1) : "h:mm:ss tt"; //$NON-NLS-1$ } /** * Returns the receiver's date, or day of the month. * <p> * The first day of the month is 1, and the last day depends on the month and year. * </p> * * @return a positive integer beginning with 1 * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> */ public int getDay () { checkWidget (); SYSTEMTIME systime = new SYSTEMTIME (); int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME; OS.SendMessage (handle, msg, 0, systime); return systime.wDay; } /** * Returns the receiver's hours. * <p> * Hours is an integer between 0 and 23. * </p> * * @return an integer between 0 and 23 * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> */ public int getHours () { checkWidget (); if ((style & SWT.CALENDAR) != 0) return time.wHour; SYSTEMTIME systime = new SYSTEMTIME (); int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME; OS.SendMessage (handle, msg, 0, systime); return systime.wHour; } /** * Returns the receiver's minutes. * <p> * Minutes is an integer between 0 and 59. * </p> * * @return an integer between 0 and 59 * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> */ public int getMinutes () { checkWidget (); if ((style & SWT.CALENDAR) != 0) return time.wMinute; SYSTEMTIME systime = new SYSTEMTIME (); int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME; OS.SendMessage (handle, msg, 0, systime); return systime.wMinute; } /** * Returns the receiver's month. * <p> * The first month of the year is 0, and the last month is 11. * </p> * * @return an integer between 0 and 11 * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> */ public int getMonth () { checkWidget (); SYSTEMTIME systime = new SYSTEMTIME (); int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME; OS.SendMessage (handle, msg, 0, systime); return systime.wMonth - 1; } String getNameText() { return (style & SWT.TIME) != 0 ? getHours() + ":" + getMinutes() + ":" + getSeconds() : (getMonth() + 1) + "/" + getDay() + "/" + getYear(); } /** * Returns the receiver's seconds. * <p> * Seconds is an integer between 0 and 59. * </p> * * @return an integer between 0 and 59 * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> */ public int getSeconds () { checkWidget (); if ((style & SWT.CALENDAR) != 0) return time.wSecond; SYSTEMTIME systime = new SYSTEMTIME (); int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME; OS.SendMessage (handle, msg, 0, systime); return systime.wSecond; } /** * Returns the receiver's year. * <p> * The first year is 1752 and the last year is 9999. * </p> * * @return an integer between 1752 and 9999 * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> */ public int getYear () { checkWidget (); SYSTEMTIME systime = new SYSTEMTIME (); int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME; OS.SendMessage (handle, msg, 0, systime); return systime.wYear; } void releaseWidget () { super.releaseWidget (); lastSystemTime = null; } /** * Removes the listener from the collection of listeners who will * be notified when the control is selected by the user. * * @param listener the listener which should no longer be notified * * @exception IllegalArgumentException <ul> * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> * </ul> * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> * * @see SelectionListener * @see #addSelectionListener */ public void removeSelectionListener (SelectionListener listener) { checkWidget (); if (listener == null) error (SWT.ERROR_NULL_ARGUMENT); if (eventTable == null) return; eventTable.unhook (SWT.Selection, listener); eventTable.unhook (SWT.DefaultSelection, listener); } /** * Sets the receiver's year, month, and day in a single operation. * <p> * This is the recommended way to set the date, because setting the year, * month, and day separately may result in invalid intermediate dates. * </p> * * @param year an integer between 1752 and 9999 * @param month an integer between 0 and 11 * @param day a positive integer beginning with 1 * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> * * @since 3.4 */ public void setDate (int year, int month, int day) { checkWidget (); if (year < MIN_YEAR || year > MAX_YEAR) return; SYSTEMTIME systime = new SYSTEMTIME (); int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME; OS.SendMessage (handle, msg, 0, systime); msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_SETCURSEL : OS.DTM_SETSYSTEMTIME; systime.wYear = (short)year; systime.wMonth = (short)(month + 1); systime.wDay = (short)day; OS.SendMessage (handle, msg, 0, systime); lastSystemTime = null; } /** * Sets the receiver's date, or day of the month, to the specified day. * <p> * The first day of the month is 1, and the last day depends on the month and year. * If the specified day is not valid for the receiver's month and year, then it is ignored. * </p> * * @param day a positive integer beginning with 1 * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> * * @see #setDate */ public void setDay (int day) { checkWidget (); SYSTEMTIME systime = new SYSTEMTIME (); int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME; OS.SendMessage (handle, msg, 0, systime); msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_SETCURSEL : OS.DTM_SETSYSTEMTIME; systime.wDay = (short)day; OS.SendMessage (handle, msg, 0, systime); lastSystemTime = null; } /** * Sets the receiver's hours. * <p> * Hours is an integer between 0 and 23. * </p> * * @param hours an integer between 0 and 23 * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> */ public void setHours (int hours) { checkWidget (); if (hours < 0 || hours > 23) return; SYSTEMTIME systime = new SYSTEMTIME (); int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME; OS.SendMessage (handle, msg, 0, systime); msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_SETCURSEL : OS.DTM_SETSYSTEMTIME; systime.wHour = (short)hours; OS.SendMessage (handle, msg, 0, systime); if ((style & SWT.CALENDAR) != 0 && hours >= 0 && hours <= 23) time.wHour = (short)hours; } /** * Sets the receiver's minutes. * <p> * Minutes is an integer between 0 and 59. * </p> * * @param minutes an integer between 0 and 59 * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> */ public void setMinutes (int minutes) { checkWidget (); if (minutes < 0 || minutes > 59) return; SYSTEMTIME systime = new SYSTEMTIME (); int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME; OS.SendMessage (handle, msg, 0, systime); msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_SETCURSEL : OS.DTM_SETSYSTEMTIME; systime.wMinute = (short)minutes; OS.SendMessage (handle, msg, 0, systime); if ((style & SWT.CALENDAR) != 0 && minutes >= 0 && minutes <= 59) time.wMinute = (short)minutes; } /** * Sets the receiver's month. * <p> * The first month of the year is 0, and the last month is 11. * If the specified month is not valid for the receiver's day and year, then it is ignored. * </p> * * @param month an integer between 0 and 11 * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> * * @see #setDate */ public void setMonth (int month) { checkWidget (); SYSTEMTIME systime = new SYSTEMTIME (); int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME; OS.SendMessage (handle, msg, 0, systime); msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_SETCURSEL : OS.DTM_SETSYSTEMTIME; systime.wMonth = (short)(month + 1); OS.SendMessage (handle, msg, 0, systime); lastSystemTime = null; } public void setOrientation (int orientation) { /* Currently supported only for CALENDAR style. */ if ((style & SWT.CALENDAR) != 0) super.setOrientation (orientation); } /** * Sets the receiver's seconds. * <p> * Seconds is an integer between 0 and 59. * </p> * * @param seconds an integer between 0 and 59 * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> */ public void setSeconds (int seconds) { checkWidget (); if (seconds < 0 || seconds > 59) return; SYSTEMTIME systime = new SYSTEMTIME (); int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME; OS.SendMessage (handle, msg, 0, systime); msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_SETCURSEL : OS.DTM_SETSYSTEMTIME; systime.wSecond = (short)seconds; OS.SendMessage (handle, msg, 0, systime); if ((style & SWT.CALENDAR) != 0 && seconds >= 0 && seconds <= 59) time.wSecond = (short)seconds; } /** * Sets the receiver's hours, minutes, and seconds in a single operation. * * @param hours an integer between 0 and 23 * @param minutes an integer between 0 and 59 * @param seconds an integer between 0 and 59 * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> * * @since 3.4 */ public void setTime (int hours, int minutes, int seconds) { checkWidget (); if (hours < 0 || hours > 23 || minutes < 0 || minutes > 59 || seconds < 0 || seconds > 59) return; SYSTEMTIME systime = new SYSTEMTIME (); int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME; OS.SendMessage (handle, msg, 0, systime); msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_SETCURSEL : OS.DTM_SETSYSTEMTIME; systime.wHour = (short)hours; systime.wMinute = (short)minutes; systime.wSecond = (short)seconds; OS.SendMessage (handle, msg, 0, systime); if ((style & SWT.CALENDAR) != 0 && hours >= 0 && hours <= 23 && minutes >= 0 && minutes <= 59 && seconds >= 0 && seconds <= 59) { time.wHour = (short)hours; time.wMinute = (short)minutes; time.wSecond = (short)seconds; } } /** * Sets the receiver's year. * <p> * The first year is 1752 and the last year is 9999. * If the specified year is not valid for the receiver's day and month, then it is ignored. * </p> * * @param year an integer between 1752 and 9999 * * @exception SWTException <ul> * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> * </ul> * * @see #setDate */ public void setYear (int year) { checkWidget (); if (year < MIN_YEAR || year > MAX_YEAR) return; SYSTEMTIME systime = new SYSTEMTIME (); int msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_GETCURSEL : OS.DTM_GETSYSTEMTIME; OS.SendMessage (handle, msg, 0, systime); msg = (style & SWT.CALENDAR) != 0 ? OS.MCM_SETCURSEL : OS.DTM_SETSYSTEMTIME; systime.wYear = (short)year; OS.SendMessage (handle, msg, 0, systime); lastSystemTime = null; } int widgetStyle () { int bits = super.widgetStyle () | OS.WS_TABSTOP; if ((style & SWT.CALENDAR) != 0) return bits | OS.MCS_NOTODAY; /* * Bug in Windows: When WS_CLIPCHILDREN is set in a * Date and Time Picker, the widget draws on top of * the updown control. The fix is to clear the bits. */ bits &= ~OS.WS_CLIPCHILDREN; if ((style & SWT.TIME) != 0) bits |= OS.DTS_TIMEFORMAT; if ((style & SWT.DATE) != 0) { bits |= ((style & SWT.MEDIUM) != 0 ? OS.DTS_SHORTDATECENTURYFORMAT : OS.DTS_LONGDATEFORMAT); if ((style & SWT.DROP_DOWN) == 0) bits |= OS.DTS_UPDOWN; } return bits; } TCHAR windowClass () { return (style & SWT.CALENDAR) != 0 ? CalendarClass : DateTimeClass; } long /*int*/ windowProc () { return (style & SWT.CALENDAR) != 0 ? CalendarProc : DateTimeProc; } LRESULT wmNotifyChild (NMHDR hdr, long /*int*/ wParam, long /*int*/ lParam) { switch (hdr.code) { case OS.DTN_CLOSEUP: { /* * Feature in Windows. When the user selects the drop-down button, * the DateTimePicker runs a modal loop and consumes WM_LBUTTONUP. * This is done without adding a mouse capture. Since WM_LBUTTONUP * is not delivered, the normal mechanism where a mouse capture is * added on mouse down and removed when the mouse is released * is broken, leaving an unwanted capture. The fix is to avoid * setting capture on mouse down right after WM_LBUTTONUP is consumed. */ display.captureChanged = true; break; } case OS.MCN_SELCHANGE: { if (ignoreSelection) break; SYSTEMTIME systime = new SYSTEMTIME (); OS.SendMessage (handle, OS.MCM_GETCURSEL, 0, systime); sendSelectionEvent (SWT.Selection); break; } case OS.DTN_DATETIMECHANGE: { SYSTEMTIME systime = new SYSTEMTIME (); OS.SendMessage (handle, OS.DTM_GETSYSTEMTIME, 0, systime); if (lastSystemTime == null || systime.wDay != lastSystemTime.wDay || systime.wMonth != lastSystemTime.wMonth || systime.wYear != lastSystemTime.wYear) { sendSelectionEvent (SWT.Selection); if ((style & SWT.TIME) == 0) lastSystemTime = systime; } break; } } return super.wmNotifyChild (hdr, wParam, lParam); } LRESULT WM_CHAR (long /*int*/ wParam, long /*int*/ lParam) { LRESULT result = super.WM_CHAR (wParam, lParam); if (result != null) return result; /* * Feature in Windows. For some reason, when the * user presses tab, return or escape, Windows beeps. * The fix is to look for these keys and not call * the window proc. */ switch ((int)/*64*/wParam) { case SWT.CR: sendSelectionEvent (SWT.DefaultSelection); // FALL THROUGH case SWT.TAB: case SWT.ESC: return LRESULT.ZERO; } return result; } LRESULT WM_LBUTTONDBLCLK (long /*int*/ wParam, long /*int*/ lParam) { LRESULT result = super.WM_LBUTTONDBLCLK (wParam, lParam); if (isDisposed ()) return LRESULT.ZERO; if ((style & SWT.CALENDAR) != 0) { MCHITTESTINFO pMCHitTest = new MCHITTESTINFO (); pMCHitTest.cbSize = MCHITTESTINFO.sizeof; POINT pt = new POINT (); pt.x = OS.GET_X_LPARAM (lParam); pt.y = OS.GET_Y_LPARAM (lParam); pMCHitTest.pt = pt; long /*int*/ code = OS.SendMessage (handle, OS.MCM_HITTEST, 0, pMCHitTest); if ((code & OS.MCHT_CALENDARDATE) == OS.MCHT_CALENDARDATE) doubleClick = true; } return result; } LRESULT WM_LBUTTONDOWN (long /*int*/ wParam, long /*int*/ lParam) { LRESULT result = super.WM_LBUTTONDOWN (wParam, lParam); if (result == LRESULT.ZERO) return result; doubleClick = false; /* * Feature in Windows. For some reason, the calendar control * does not take focus on WM_LBUTTONDOWN. The fix is to * explicitly set focus. */ if ((style & SWT.CALENDAR) != 0) { if ((style & SWT.NO_FOCUS) == 0) OS.SetFocus (handle); } return result; } LRESULT WM_LBUTTONUP (long /*int*/ wParam, long /*int*/ lParam) { LRESULT result = super.WM_LBUTTONUP (wParam, lParam); if (isDisposed ()) return LRESULT.ZERO; if (doubleClick) sendSelectionEvent (SWT.DefaultSelection); doubleClick = false; return result; } LRESULT WM_TIMER (long /*int*/ wParam, long /*int*/ lParam) { LRESULT result = super.WM_TIMER (wParam, lParam); if (result != null) return result; /* * Feature in Windows. For some reason, Windows sends WM_NOTIFY with * MCN_SELCHANGE at regular intervals. This is unexpected. The fix is * to ignore MCN_SELCHANGE during WM_TIMER. */ ignoreSelection = true; long /*int*/ code = callWindowProc(handle, OS.WM_TIMER, wParam, lParam); ignoreSelection = false; return code == 0 ? LRESULT.ZERO : new LRESULT(code); } }